package com.run_java_test.jar_upload_run.services.v2;

import com.alibaba.fastjson2.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

// jar上传的服务类
@Service
public class JarUploadService {

    // 用于存储 controller 的映射信息
    private final Map<RequestMappingInfo, Object> registeredControllers = new ConcurrentHashMap<>();
    // ----------------------------------------------------------------------------------------------------------------


    // 引入需要使用的bean组件
    // ----------------------------------------------------------------------------------------------------------------
    // bean注册器
    private final DefaultListableBeanFactory defaultListableBeanFactory;
    // spring 上下文
    private final ApplicationContext applicationContext;
    // 请求地址和方法映射处理类
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    public JarUploadService(
            DefaultListableBeanFactory defaultListableBeanFactory,
            ApplicationContext applicationContext,
            RequestMappingHandlerMapping requestMappingHandlerMapping
    ) {
        this.defaultListableBeanFactory = defaultListableBeanFactory;
        this.applicationContext = applicationContext;
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
    }
    // ----------------------------------------------------------------------------------------------------------------

    /**
     * 注册jar中的controller
     *
     * @param controllerClass 类
     */
    public void registerController(Class<?> controllerClass) {
        // 如果类上面有controller相关注解
        if (controllerClass.isAnnotationPresent(RestController.class)) {
            // 检查类级别路径
            String[] classLevelPaths = {};
            // 获取类级别路径
            if (controllerClass.isAnnotationPresent(RequestMapping.class)) {
                RequestMapping classRequestMapping = controllerClass.getAnnotation(RequestMapping.class);
                classLevelPaths = classRequestMapping.value();
            }

            // 因为controller已经被类注册器注册完成, 并且被实例化, 现在只需要注册路径和controller中的方法映射
            try {
                // 获取类名并将首字母小写, 这个是统一作为bean名称
                String beanName = controllerClass.getSimpleName();
                beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);

                // 获取 controller 这个 bean
                Object controllerInstance = applicationContext.getBean(beanName);

                // 获取类的所有方法
                Method[] declaredMethods = controllerClass.getDeclaredMethods();

                // 遍历 controller 的所有方法
                for (int i = 0; i < declaredMethods.length; i++) {
                    // 获取一个方法
                    Method method = declaredMethods[i];

                    // 获取被 RequestMapping 注解标识的方法
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        // 获取 RequestMapping 注解
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);

                        // 合并类级别路径和方法级别路径
                        String[] fullPaths = this.combinePaths(classLevelPaths, requestMapping.value());
                        System.out.println("注册 路径和方法映射 查看 RequestMapping fullPaths : " + JSON.toJSONString(fullPaths));

                        // 创建 RequestMappingInfo 用来构造
                        RequestMappingInfo mappingInfo = RequestMappingInfo
                                .paths(fullPaths) // 路径
                                .methods(requestMapping.method()) // 设置方法类型为 requestMapping 中定义的
                                .produces(requestMapping.produces()) // 返回类型
                                .consumes(requestMapping.consumes()) // 消费类型
                                .build();

                        // 注册 HandlerMethod, 注册请求地址对应的方法
                        requestMappingHandlerMapping.registerMapping(mappingInfo, controllerInstance, method);

                        System.out.println("注册 RequestMapping 类型的方法成功");

                        // 保存注册的信息
                        registeredControllers.put(mappingInfo, controllerInstance);
                    }

                    // 获取被 GetMapping 注解标识的方法
                    if (method.isAnnotationPresent(GetMapping.class)) {
                        // 获取 GetMapping 注解
                        GetMapping requestMapping = method.getAnnotation(GetMapping.class);

                        // 合并类级别路径和方法级别路径
                        String[] fullPaths = this.combinePaths(classLevelPaths, requestMapping.value());
                        System.out.println("注册 路径和方法映射 查看 GetMapping fullPaths : " + JSON.toJSONString(fullPaths));

                        // 构造 RequestMappingInfo
                        RequestMappingInfo mappingInfo = RequestMappingInfo
                                .paths(fullPaths) // 路径
                                .methods(RequestMethod.GET) // 强制指定为 GET 方法
                                .produces(requestMapping.produces()) // 返回类型
                                .consumes(requestMapping.consumes()) // 消费类型
                                .build();

                        // 注册 HandlerMethod
                        requestMappingHandlerMapping.registerMapping(mappingInfo, controllerInstance, method);

                        System.out.println("注册 GetMapping 类型的方法成功");

                        // 保存注册的信息
                        registeredControllers.put(mappingInfo, controllerInstance);
                    }
                }
            } catch (Exception e) {
                System.out.println("注册bean出现异常 : " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
    // ----------------------------------------------------------------------------------------------------------------

    /**
     * 注销jar中的controller
     *
     * @param controllerClass controller的类
     */
    public void unregisterController(Class<?> controllerClass) {
        // 如果这个类是controller类型
        if (controllerClass.isAnnotationPresent(RestController.class)) {
            // 检查类级别路径
            String[] classLevelPaths = {};
            // 类上是否存在 RequestMapping
            if (controllerClass.isAnnotationPresent(RequestMapping.class)) {
                RequestMapping classRequestMapping = controllerClass.getAnnotation(RequestMapping.class);
                classLevelPaths = classRequestMapping.value();
            }

            // 处理 controller 中的方法
            for (Method method : controllerClass.getDeclaredMethods()) {
                // 如果方法是 RequestMapping 类型 的请求
                if (method.isAnnotationPresent(RequestMapping.class)) {
                    // RequestMapping 注解
                    RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);

                    // 合并类级别路径和方法级别路径
                    String[] fullPaths = this.combinePaths(classLevelPaths, requestMapping.value());
                    System.out.println("卸载 路径和方法映射 查看 RequestMapping fullPaths : " + JSON.toJSONString(fullPaths));

                    // RequestMappingInfo 构造处理
                    RequestMappingInfo mappingInfo = RequestMappingInfo
                            .paths(fullPaths)
                            .methods(requestMapping.method())
                            .produces(requestMapping.produces())
                            .consumes(requestMapping.consumes())
                            .build();

                    // 去除保存的映射, 返回之前的内容
                    Object controllerInstance = registeredControllers.remove(mappingInfo);

                    // 如果之前保存了值, 去springmvc中注销映射
                    if (controllerInstance != null) {
                        // 注销映射
                        requestMappingHandlerMapping.unregisterMapping(mappingInfo);
                    }
                }

                // 如果是 get 类型的请求
                if (method.isAnnotationPresent(GetMapping.class)) {
                    // GetMapping 注解
                    GetMapping requestMapping = method.getAnnotation(GetMapping.class);

                    // 合并类级别路径和方法级别路径
                    String[] fullPaths = this.combinePaths(classLevelPaths, requestMapping.value());
                    System.out.println("卸载 路径和方法映射 查看 GetMapping fullPaths : " + JSON.toJSONString(fullPaths));

                    // RequestMappingInfo 构造处理
                    RequestMappingInfo mappingInfo = RequestMappingInfo
                            .paths(fullPaths)
                            .methods(RequestMethod.GET)
                            .produces(requestMapping.produces())
                            .consumes(requestMapping.consumes())
                            .build();

                    // 去除保存的映射, 返回之前的内容
                    Object controllerInstance = registeredControllers.remove(mappingInfo);

                    // 如果之前保存了值, 去springmvc中注销映射
                    if (controllerInstance != null) {
                        // 注销映射
                        requestMappingHandlerMapping.unregisterMapping(mappingInfo);
                    }
                }
            }
            System.out.println("注销了类对应的controller映射, 类名称 : " + controllerClass.getSimpleName());
        }
    }
    // ----------------------------------------------------------------------------------------------------------------

    /**
     * 合并路径方法
     *
     * @param classLevelPaths
     * @param methodLevelPaths
     * @return
     */
    private String[] combinePaths(String[] classLevelPaths, String[] methodLevelPaths) {
        if (classLevelPaths.length == 0) {
            return methodLevelPaths; // 没有类级别路径，直接返回方法级别路径
        }
        List<String> combinedPaths = new ArrayList<>();
        for (String classPath : classLevelPaths) {
            for (String methodPath : methodLevelPaths) {
                String combinedPath = classPath + "/" + methodPath;
                combinedPaths.add(combinedPath.replaceAll("//+", "/")); // 确保路径中不会出现多个连续的斜杠
            }
        }
        return combinedPaths.toArray(new String[0]);
    }
    // ----------------------------------------------------------------------------------------------------------------

}
